#ifndef _MATH_H_
#define _MATH_H_

#include <math.h>

#ifdef max
#undef max
#endif

#ifdef min
#undef min
#endif

__declspec(align(16))
struct Vec4
{
	float x;
	float y;
	float z;
	float w;

	Vec4(float _x, float _y, float _z, float _w)
		:x(_x),
		y(_y),
		z(_z),
		w(_w)
	{}

	Vec4(float value)
		:x(value),
		y(value),
		z(value),
		w(value)
	{}

	Vec4()
	{}
};

namespace CGen
{
	inline float log2(float a)
	{
		return log(a) / log(2.0f);
	}

	inline const Vec4& Vec4Zero()
	{
		static const Vec4 retValue(0.0f);
		return retValue;
	}

	inline void Vec4SetFloat(Vec4* vector, float value)
	{
		vector->x = vector->y = vector->z = vector->w = value;
	}

	inline void Vec4Scale(Vec4 *outVec, const Vec4* vector, float scale)
	{
		outVec->x = vector->x * scale;
		outVec->y = vector->y * scale;
		outVec->z = vector->z * scale;
	}

	inline void Vec4Scalew(Vec4 *outVec, const Vec4* vector, float scale)
	{
		outVec->x = vector->x * scale;
		outVec->y = vector->y * scale;
		outVec->z = vector->z * scale;
		outVec->w = vector->w * scale;
	}

	inline void Vec4Add(Vec4 *outVec, const Vec4* vector1, const Vec4* vector2)
	{
		outVec->x = vector1->x + vector2->x;
		outVec->y = vector1->y + vector2->y;
		outVec->z = vector1->z + vector2->z;
		outVec->w = vector1->w + vector2->w;
	}

	inline void Vec4Abs(Vec4 *outVec, const Vec4* vector1)
	{
		outVec->x = abs(vector1->x);
		outVec->y = abs(vector1->y);
		outVec->z = abs(vector1->z);
		outVec->w = abs(vector1->w);
	}

	inline float Vec4Lengthw(const Vec4 *vector)
	{
		return sqrtf(vector->x * vector->x + vector->y * vector->y + vector->z * vector->z + vector->w * vector->w);
	}

	inline void Vec4Normalizew(Vec4 *outVec, const Vec4* vector)
	{
		float scale = 1.0f / Vec4Lengthw(vector);
		Vec4Scalew(outVec, vector, scale);
	}

	inline float Vec4Length(const Vec4 *vector)
	{
		return sqrtf(vector->x * vector->x + vector->y * vector->y + vector->z * vector->z);
	}

	inline float Vec4Dotp(const Vec4* v1, const Vec4* v2)
	{
		return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
	}

	inline void Vec4Normalize(Vec4 *outVec, const Vec4* vector)
	{
		float scale = 1.0f / Vec4Length(vector);
		Vec4Scale(outVec, vector, scale);
	}

	template <typename T>
	inline T max(T a, T b)
	{
		return a > b ? a : b;
	}

	template <typename T>
	inline T min(T a, T b)
	{
		return a < b ? a : b;
	}
}

#endif